﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Security.Permissions;

namespace OccupierArchiver.Helpers
{
    /// <summary>
    ///     Provides properties for getting the information about the application, such as the version number, description,
    ///     loaded assemblies, and so on.
    /// </summary>
    /// <filterpriority>1</filterpriority>
    [HostProtection(SecurityAction.LinkDemand, Resources = HostProtectionResource.ExternalProcessMgmt)]
    public class AssemblyInfo
    {
        private readonly Assembly _assembly;
        private string _companyName;
        private string _copyright;
        private string _description;
        private string _productName;
        private string _title;
        private string _trademark;

        /// <summary>
        ///     Initializes a new instance of the AssemblyInfo class with the specified assembly information.
        /// </summary>
        /// <param name="currentAssembly">
        ///     <see cref="T:System.Reflection.Assembly" />. The assembly for which to obtain the information.
        /// </param>
        public AssemblyInfo(Assembly currentAssembly)
        {
            if (currentAssembly == null)
            {
                throw new ArgumentNullException("currentAssembly", @"Argument cannot be null.");
            }
            _assembly = currentAssembly;
        }

        /// <summary>
        ///     Gets the name, without the extension, of the assembly file for the application.
        /// </summary>
        /// <returns>
        ///     A String containing the file name.
        /// </returns>
        public string AssemblyName
        {
            get { return _assembly.GetName().Name; }
        }

        /// <summary>
        ///     Gets the company name associated with the application.
        /// </summary>
        /// <returns>
        ///     A String that contains the company name associated with the application.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public string CompanyName
        {
            get
            {
                if (_companyName == null)
                {
                    var attribute = (AssemblyCompanyAttribute)GetAttribute(typeof(AssemblyCompanyAttribute));
                    if (attribute == null)
                    {
                        _companyName = "";
                    }
                    else
                    {
                        _companyName = attribute.Company;
                    }
                }
                return _companyName;
            }
        }

        /// <summary>
        ///     Gets the copyright notice associated with the application.
        /// </summary>
        /// <returns>
        ///     A String containing the copyright notice associated with the application.
        /// </returns>
        public string Copyright
        {
            get
            {
                if (_copyright == null)
                {
                    var attribute = (AssemblyCopyrightAttribute)GetAttribute(typeof(AssemblyCopyrightAttribute));
                    if (attribute == null)
                    {
                        _copyright = "";
                    }
                    else
                    {
                        _copyright = attribute.Copyright;
                    }
                }
                return _copyright;
            }
        }

        /// <summary>
        ///     Gets the description associated with the application.
        /// </summary>
        /// <returns>
        ///     A String containing the description associated with the application.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public string Description
        {
            get
            {
                if (_description == null)
                {
                    var attribute = (AssemblyDescriptionAttribute)GetAttribute(typeof(AssemblyDescriptionAttribute));
                    if (attribute == null)
                    {
                        _description = "";
                    }
                    else
                    {
                        _description = attribute.Description;
                    }
                }
                return _description;
            }
        }

        /// <summary>
        ///     Gets the directory where the application is stored.
        /// </summary>
        /// <returns>
        ///     A String that contains the directory where the application is stored.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        /// <PermissionSet>
        ///     <IPermission
        ///         class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        ///         version="1" Unrestricted="true" />
        /// </PermissionSet>
        public string DirectoryPath
        {
            get { return Path.GetDirectoryName(_assembly.Location); }
        }

        /// <summary>
        ///     Gets a collection of all assemblies loaded by the application.
        /// </summary>
        /// <returns>
        ///     A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1" /> of
        ///     <see cref="T:System.Reflection.Assembly" /> containing all the assemblies loaded by the application.
        /// </returns>
        public ReadOnlyCollection<Assembly> LoadedAssemblies
        {
            get
            {
                var list = new Collection<Assembly>();
                foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    list.Add(assembly);
                }
                return new ReadOnlyCollection<Assembly>(list);
            }
        }

        /// <summary>
        ///     Gets the product name associated with the application.
        /// </summary>
        /// <returns>
        ///     A String containing the product name associated with the application.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public string ProductName
        {
            get
            {
                if (_productName == null)
                {
                    var attribute = (AssemblyProductAttribute)GetAttribute(typeof(AssemblyProductAttribute));
                    if (attribute == null)
                    {
                        _productName = "";
                    }
                    else
                    {
                        _productName = attribute.Product;
                    }
                }
                return _productName;
            }
        }

        /// <summary>
        ///     Gets the current stack-trace information.
        /// </summary>
        /// <returns>
        ///     A String containing the current stack-trace information. The return value can be
        ///     <see cref="F:System.String.Empty" />.
        /// </returns>
        public string StackTrace
        {
            get { return Environment.StackTrace; }
        }

        /// <summary>
        ///     Gets the title associated with the application.
        /// </summary>
        /// <returns>
        ///     A String containing the <see cref="T:System.Reflection.AssemblyTitleAttribute" /> associated with the application.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        public string Title
        {
            get
            {
                if (_title == null)
                {
                    var attribute = (AssemblyTitleAttribute)GetAttribute(typeof(AssemblyTitleAttribute));
                    if (attribute == null)
                    {
                        _title = "";
                    }
                    else
                    {
                        _title = attribute.Title;
                    }
                }
                return _title;
            }
        }

        /// <summary>
        ///     Gets the trademark notice associated with the application.
        /// </summary>
        /// <returns>
        ///     A String containing the trademark notice associated with the application.
        /// </returns>
        public string Trademark
        {
            get
            {
                if (_trademark == null)
                {
                    var attribute = (AssemblyTrademarkAttribute)GetAttribute(typeof(AssemblyTrademarkAttribute));
                    if (attribute == null)
                    {
                        _trademark = "";
                    }
                    else
                    {
                        _trademark = attribute.Trademark;
                    }
                }
                return _trademark;
            }
        }

        /// <summary>
        ///     Gets the version number of the application.
        /// </summary>
        /// <returns>
        ///     A <see cref="T:System.Version" /> object containing the version number of the application.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        /// <PermissionSet>
        ///     <IPermission
        ///         class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        ///         version="1" Unrestricted="true" />
        /// </PermissionSet>
        public Version Version
        {
            get { return _assembly.GetName().Version; }
        }

        /// <summary>
        ///     Gets the amount of physical memory mapped to the process context.
        /// </summary>
        /// <returns>
        ///     A Long containing the number of bytes of physical memory mapped to the process context.
        /// </returns>
        public long WorkingSet
        {
            get { return Environment.WorkingSet; }
        }

        private object GetAttribute(Type attributeType)
        {
            var customAttributes = _assembly.GetCustomAttributes(attributeType, true);
            if (customAttributes.Length == 0)
            {
                return null;
            }
            return customAttributes[0];
        }
    }
}
